

#include "SceneEditor.h"
#include "SceneEditorDoc.h"
#include "SceneImageLoader.h"
#include "SceneImageSaver.h"
#include "ImageInfo.h"


SceneEditorDoc::SceneEditorDoc(QObject *parent)
    : QDocument(parent)
{

}

SceneEditorDoc::~SceneEditorDoc()
{

}

bool SceneEditorDoc::loadData()
{
    loadImages();

    return true;
}

bool SceneEditorDoc::saveData()
{
    saveImages();

    return true;
}

bool SceneEditorDoc::loadImages()
{
    QString filename = mSceneInfo.value(SCN_IMG_INFO_FILE_KEY).toString();
    QString imagePath = location() + "Image/";
    QString filePath = location() + filename + SCN_IMG_INFO_FILE_EXT;

    SceneImageLoader *loader = new SceneImageLoader(imagePath, filePath);
    QThread *thread = new QThread();
    loader->moveToThread(thread);

    connect(thread, SIGNAL(started()), loader, SLOT(run()));
    connect(thread, SIGNAL(finished()), loader, SLOT(deleteLater()));
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    connect(loader, SIGNAL(started()), SLOT(onLoadingStarted()));
    connect(loader, SIGNAL(totalSteps(int)), SLOT(onLoadingTotalStep(int)));
    connect(loader, SIGNAL(progress(int,ImageInfo*,int,QGraphicsPixmapItem*)), SLOT(onLoadingProgress(int,ImageInfo*,int,QGraphicsPixmapItem*)));
    connect(loader, SIGNAL(finished(int,QString)), SLOT(onLoadingFinished(int,QString)));

    thread->start();

    return true;
}

bool SceneEditorDoc::saveImages()
{
    QString filePath = location() + title() + SCN_IMG_INFO_FILE_EXT;

    SceneImageSaver *saver = new SceneImageSaver(mBkgndInfoList, mMaskInfoList, filePath);
    QThread *thread = new QThread();
    saver->moveToThread(thread);

    connect(thread, SIGNAL(started()), saver, SLOT(run()));
    connect(thread, SIGNAL(finished()), saver, SLOT(deleteLater()));
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

    thread->start();

    return true;
}

bool SceneEditorDoc::insertImage(const QString &filePath, ImageMode mode)
{
    QString path = location() + "Image/";
    ImageInfo *info = new ImageInfo(path, filePath);

    if (0 == info)
    {
        return false;
    }

    if (ImageBkgnd == mode)
    {
        mBkgndInfoList.push_back(info);
    }
    else if (ImageMask == mode)
    {
        mMaskInfoList.push_back(info);
    }
    else
    {
        return false;
    }

    if (!mBkgndInfoList.isEmpty() || !mMaskInfoList.isEmpty())
    {
        QString val = title();
        QVariant var(val);
        mSceneInfo.insert(SCN_IMG_INFO_FILE_KEY, var);
    }

    QGraphicsPixmapItem *item = new QGraphicsPixmapItem(info->image());

    setModifiedFlag(true);

    emit imageInserted(info, item, mode);

    return true;
}

bool SceneEditorDoc::deleteImageByIndex(int index)
{
    int numberOfBkgnd = mBkgndInfoList.size();
    int numberOfMask = mMaskInfoList.size();

    int numberOfImages = numberOfBkgnd + numberOfMask;

    qint64 key = 0;
    int idx = 0;
    QImageInfoList *infoList = 0;

    if (index >= 0 && index < numberOfBkgnd)
    {
        idx = index;
        infoList = &mBkgndInfoList;
    }
    else if (index >= numberOfBkgnd && index < numberOfImages)
    {
        idx = index - numberOfBkgnd;
        infoList = &mMaskInfoList;
    }
    else
    {
        return false;
    }

    bool found = false;
    int i = 0;
    QImageInfoListItr itr = infoList->begin();
    while (itr != infoList->end())
    {
        if (i == idx)
        {
            ImageInfo *info = *itr;
            key = info->image().cacheKey();
            delete info;
            infoList->erase(itr);
            found = true;
            break;
        }

        ++itr;
    }

    if (found)
    {
        if (mBkgndInfoList.isEmpty() && mMaskInfoList.isEmpty())
        {
            mSceneInfo.remove(SCN_IMG_INFO_FILE_KEY);
        }

        setModifiedFlag(true);

        emit imageDeleted(index, key);
    }

    return found;
}

bool SceneEditorDoc::deleteImageByKey(qint64 cacheKey)
{
    int i = 0;
    bool found = false;
    QImageInfoListItr itr = mBkgndInfoList.begin();
    while (itr != mBkgndInfoList.end())
    {
        ImageInfo *info = *itr;
        if (cacheKey == info->cacheKey())
        {
            found = true;
            mBkgndInfoList.erase(itr);
            break;
        }

        ++i;
        ++itr;
    }

    if (!found)
    {
        itr = mMaskInfoList.begin();
        while (itr != mMaskInfoList.end())
        {
            ImageInfo *info = *itr;
            if (cacheKey == info->cacheKey())
            {
                found = true;
                mMaskInfoList.erase(itr);
                break;
            }

            ++i;
            ++itr;
        }
    }

    if (found)
    {
        if (mBkgndInfoList.isEmpty() && mMaskInfoList.isEmpty())
        {
            mSceneInfo.remove(SCN_IMG_INFO_FILE_KEY);
        }

        setModifiedFlag(true);

        emit imageDeleted(i, cacheKey);
    }

    return found;
}

bool SceneEditorDoc::adjustImagePositionByIndex(int index, const QPoint &pos)
{
    int numberOfBkgnd = mBkgndInfoList.size();
    int numberOfMask = mMaskInfoList.size();

    int numberOfImages = numberOfBkgnd + numberOfMask;

    qint64 key = 0;
    int idx = 0;
    QImageInfoList *infoList = 0;

    if (index >= 0 && index < numberOfBkgnd)
    {
        idx = index;
        infoList = &mBkgndInfoList;
    }
    else if (index >= numberOfBkgnd && index < numberOfImages)
    {
        idx = index - numberOfBkgnd;
        infoList = &mMaskInfoList;
    }
    else
    {
        return false;
    }

    bool found = false;
    int i = 0;
    QImageInfoListItr itr = infoList->begin();
    while (itr != infoList->end())
    {
        if (i == idx)
        {
            ImageInfo *info = *itr;
            key = info->image().cacheKey();
            info->setPosition(pos);
            break;
        }

        ++itr;
    }

    if (found)
    {
        setModifiedFlag(true);

        emit imagePositionAdjusted(index, key, pos);
    }

    return found;
}

bool SceneEditorDoc::adjustImagePositionByKey(qint64 cacheKey, const QPoint &pos)
{
    int i = 0;
    bool found = false;
    QImageInfoListItr itr = mBkgndInfoList.begin();
    while (itr != mBkgndInfoList.end())
    {
        ImageInfo *info = *itr;
        if (cacheKey == info->cacheKey())
        {
            found = true;
            info->setPosition(pos);
            break;
        }

        ++i;
        ++itr;
    }

    if (!found)
    {
        itr = mMaskInfoList.begin();
        while (itr != mMaskInfoList.end())
        {
            ImageInfo *info = *itr;
            if (cacheKey == info->cacheKey())
            {
                found = true;
                info->setPosition(pos);
                break;
            }

            ++i;
            ++itr;
        }
    }

    if (found)
    {
        if (mBkgndInfoList.isEmpty() && mMaskInfoList.isEmpty())
        {
            mSceneInfo.remove(SCN_IMG_INFO_FILE_KEY);
        }

        setModifiedFlag(true);

        emit imageDeleted(i, cacheKey);
    }

    return found;
}

bool SceneEditorDoc::modifyImageModeByIndex(int index, ImageMode mode)
{
    int numberOfBkgnd = mBkgndInfoList.size();
    int numberOfMask = mMaskInfoList.size();

    int numberOfImages = numberOfBkgnd + numberOfMask;

    qint64 key = 0;
    int idx = 0;
    QImageInfoList *infoList = 0;
    ImageMode srcMode;

    if (index >= 0 && index < numberOfBkgnd)
    {
        idx = index;
        infoList = &mBkgndInfoList;
        srcMode = ImageBkgnd;
    }
    else if (index >= numberOfBkgnd && index < numberOfImages)
    {
        idx = index - numberOfBkgnd;
        infoList = &mMaskInfoList;
        srcMode = ImageMask;
    }
    else
    {
        return false;
    }

    bool found = false;
    int i = 0;
    QImageInfoListItr itr = infoList->begin();
    while (itr != infoList->end())
    {
        if (i == idx)
        {
            if (mode != srcMode)
            {
                ImageInfo *info = *itr;
                key = info->image().cacheKey();
                infoList->erase(itr);

                if (mode == ImageBkgnd)
                {
                    mBkgndInfoList.push_back(info);
                }
                else
                {
                    mMaskInfoList.push_back(info);
                }

                found = true;
            }
            break;
        }

        ++itr;
    }

    if (found)
    {
        setModifiedFlag(true);

        emit imageModeModified(index, key, mode);
    }

    return found;
}

bool SceneEditorDoc::modifyImageModeByKey(qint64 cacheKey, ImageMode mode)
{
    int i = 0;
    bool found = false;
    bool result = false;
    QImageInfoListItr itr = mBkgndInfoList.begin();
    while (itr != mBkgndInfoList.end())
    {
        ImageInfo *info = *itr;
        if (cacheKey == info->cacheKey())
        {
            found = true;
            if (mode == ImageMask)
            {
                mBkgndInfoList.erase(itr);
                mMaskInfoList.push_back(info);
                result = true;
            }
            break;
        }

        ++i;
        ++itr;
    }

    if (!found && !result)
    {
        itr = mMaskInfoList.begin();
        while (itr != mMaskInfoList.end())
        {
            ImageInfo *info = *itr;
            if (cacheKey == info->cacheKey())
            {
                found = true;
                if (mode == ImageBkgnd)
                {
                    mMaskInfoList.erase(itr);
                    mBkgndInfoList.push_back(info);
                    result = true;
                }
                break;
            }

            ++i;
            ++itr;
        }
    }

    if (found && result)
    {
        setModifiedFlag(true);

        emit imageModeModified(i, cacheKey, mode);
    }

    return found;
}

bool SceneEditorDoc::swapImageOrder(int srcIdx, int dstIdx)
{
    int numberOfBkgnd = mBkgndInfoList.size();
    int numberOfMask = mMaskInfoList.size();

    int numberOfImages = numberOfBkgnd + numberOfMask;

    qint64 key = 0;
    int srcIndex = 0, dstIndex = 0;
    QImageInfoList *infoList = 0;

    if (srcIdx >= 0 && srcIdx < numberOfBkgnd
        && dstIdx >= 0 && dstIdx < numberOfBkgnd)
    {
        srcIndex = srcIdx;
        dstIndex = dstIdx;
        infoList = &mBkgndInfoList;
    }
    else if (srcIdx >= numberOfBkgnd && srcIdx < numberOfImages
        && dstIdx >= numberOfBkgnd && dstIdx < numberOfImages)
    {
        srcIndex = srcIdx - numberOfBkgnd;
        dstIndex = dstIdx - numberOfBkgnd;
        infoList = &mMaskInfoList;
    }
    else
    {
        return false;
    }


    ImageInfo *srcInfo = infoList->at(srcIndex);
    ImageInfo *dstInfo = infoList->at(dstIndex);

    qint64 srcKey = srcInfo->image().cacheKey();
    qint64 dstKey = dstInfo->image().cacheKey();

    infoList->swap(srcIndex, dstIndex);

    emit imageOrderSwaped(srcIdx, dstIdx, srcKey, dstKey);

    return true;
}


bool SceneEditorDoc::onCreateDocument()
{
    QString val = SCENE_EDITOR_APP_NAME;
    QVariant var(val);
    mSceneInfo.insert(SCN_APP_KEY, var);
    val = SCENE_EDITOR_VERSION_STR;
    var = qVariantFromValue(val);
    mSceneInfo.insert(SCN_VERSION_KEY, var);

    QFile *file = fileObject();

    bool result = mSceneInfo.archive(file);

    return result;
}

bool SceneEditorDoc::onOpenDocument()
{
    QFile *file = fileObject();

    mSceneInfo.unarchive(file);
    return loadData();
}

bool SceneEditorDoc::onSaveDocument()
{
    QFile *file = fileObject();

    saveData();
    return mSceneInfo.archive(file);
}

void SceneEditorDoc::onCloseDocument()
{
    mSceneInfo.clear();
}

void SceneEditorDoc::onLoadingStarted()
{

}

void SceneEditorDoc::onLoadingTotalStep(int total)
{
    emit loadingStarted(total);
}

void SceneEditorDoc::onLoadingProgress(int step, ImageInfo *info, int mode, QGraphicsPixmapItem *item)
{
    emit imageInserted(info, item, mode);
    emit loadingProgress(step, info->name());
}

void SceneEditorDoc::onLoadingFinished(int result, const QString &msg)
{
    emit loadingFinished(result, msg);
}

void SceneEditorDoc::onSavingStarted()
{

}

void SceneEditorDoc::onSavingTotalStep(int total)
{
    emit savingStarted(total);
}

void SceneEditorDoc::onSavingProgress(int step, const QString &file)
{
    emit savingProgress(step, file);
}

void SceneEditorDoc::onSavingFinished(int result, const QString &msg)
{
    emit savingFinished(result, msg);
}
